package com.hc.programming.tree;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 给你一个含重复值的二叉搜索树（BST）的根节点 root ，找出并返回 BST 中的所有 众数（即，出现频率最高的元素）。
 * 如果树中有不止一个众数，可以按 任意顺序 返回。
 * 假定 BST 满足如下定义：
 * * 结点左子树中所含节点的值 小于等于 当前节点的值
 * * 结点右子树中所含节点的值 大于等于 当前节点的值
 * * 左子树和右子树都是二叉搜索树
 * <p>
 * 示例 1：
 * <a href="./二叉搜索树中的众数-示例1.png">示例1</a>
 * 输入：root = [1,null,2,2]
 * 输出：[2]
 * 示例 2：
 * 输入：root = [0]
 * 输出：[0]
 * <p>
 * 提示：
 * 树中节点的数目在范围 [1, 10^4] 内
 * -10^5 <= Node.val <= 10^5
 * <p>
 * 进阶：你可以不使用额外的空间吗？（假设由递归产生的隐式调用栈的开销不被计算在内）
 *
 * @author huangchao E-mail:fengquan8866@163.com
 * @version 创建时间：2024/10/16 12:35
 */
public class 二叉搜索树中的众数 {
    public static void main(String[] args) {
        Integer[] arr = new Integer[]{1, null, 2, 2};
        TreeNode tree = TreeNode.tree(arr);
        System.out.println(Arrays.toString(arr) + "=2,--" + Arrays.toString(findMode(tree)));
        arr = new Integer[]{0};
        tree = TreeNode.tree(arr);
        System.out.println(Arrays.toString(arr) + "=0,--" + Arrays.toString(findMode(tree)));
        arr = new Integer[]{6, 2, 8, 0, 4, 7, 9, null, null, 2, 6};
        tree = TreeNode.tree(arr);
        System.out.println(Arrays.toString(arr) + "=2,6,--" + Arrays.toString(findMode(tree)));
    }

    public static int[] findMode(TreeNode root) {
        // 方案1：全局记录数量
//        return 中序记录count(root);

        // 方案2：全局记录数量+pre值
        return 中序记录countWithPre(root);
    }

    private static Integer pre = null;

    /**
     * 方案2：全局记录数量+pre值
     * 合适才记录
     */
    private static int[] 中序记录countWithPre(TreeNode root) {
        maxCount = 0;
        pre = null;
        List<Integer> list = new ArrayList<>();
        中序递归2(root, list);
        int[] res = new int[list.size()];
        for (int i = 0; i < list.size(); i++) res[i] = list.get(i);
        return res;
    }

    private static void 中序递归2(TreeNode root, List<Integer> list) {
        if (root.left != null) 中序递归2(root.left, list);
        // 计数
        if (pre == null || pre != root.val) count = 1;
        else count++;
        // 记录
        if (count > maxCount) {
            list.clear();
            list.add(root.val);
            maxCount = count;
        } else if (count == maxCount) {
            list.add(root.val);
        }
        pre = root.val;
        if (root.right != null) 中序递归2(root.right, list);
    }

    /**
     * 方案1：全局记录数量
     * 有值先记录，不合适再扣减
     */
    private static int[] 中序记录count(TreeNode root) {
        count = 0;
        List<Integer> list = new ArrayList<>();
        中序递归(root, list);
        if (maxCount > count) list.remove(list.size() - 1);
        int[] res = new int[list.size()];
        for (int i = 0; i < list.size(); i++) res[i] = list.get(i);
        return res;
    }

    private static int maxCount = 0;
    private static int count = 0;

    private static void 中序递归(TreeNode root, List<Integer> list) {
        if (root.left != null) 中序递归(root.left, list);
        if (list.isEmpty() || list.get(list.size() - 1) != root.val) {
            if (count < maxCount && list.size() > 1) list.remove(list.size() - 1);
            else maxCount = count;
            count = 1;
            list.add(root.val);
        } else {
            count++;
            if (count > maxCount && list.size() > 1) {
                // 清空之前的众数
                list.clear();
                list.add(root.val);
            }
        }
        if (root.right != null) 中序递归(root.right, list);
    }

}
